<script setup lang="ts">
import type {UnwrapRef} from 'vue';
import {reactive, ref} from 'vue';
import mammoth from 'mammoth';
import _ from 'underscore';
import {errorMessage, escapeHTMLManually, getImageInfoFromBase64} from '@/utils/utils';
import {contentFillAction, stepGenerateAction} from '@/service/api';

defineOptions({
  name: 'WriteDrawer'
});

interface Props {
  taskId?: number;
  paragraphTitle?: string;
  zhaobiaoPath?: string;
  infoPath?: string;
}

const props = defineProps<Props>();

interface Emits {
  (e: 'saveWrite', value: UnwrapRef<string>): string;
}

const showLoading = ref<boolean>(false);
const loadingDes = ref<string>('正在处理中，请稍后...');

const contentHtml = ref<string>('');
const writeContentHtml = ref<string>('');
const imgList = ref<any[]>([]);
const IMAGE_TAG: string = 'WRITE_IMAGE_TAG';

// 编辑器配置
const editorConfig: object = reactive({
  serverUrl: '',
  UEDITOR_HOME_URL: '/modules/bidWriting/UEditorPlus/',
  UEDITOR_CORS_URL: '/modules/bidWriting/UEditorPlus/',
  toolbars: [
    [
      'undo',
      'redo',
      '|',
      'bold',
      'italic',
      'underline',
      'fontborder',
      'strikethrough',
      'superscript',
      'subscript',
      'removeformat',
      'formatmatch',
      'autotypeset',
      'blockquote',
      'pasteplain',
      '|',
      'forecolor',
      'backcolor',
      'insertorderedlist',
      'insertunorderedlist',
      'selectall',
      'cleardoc',
      '|',
      'rowspacingtop',
      'rowspacingbottom',
      'lineheight',
      '|',
      'customstyle',
      'paragraph',
      'fontfamily',
      'fontsize',
      '|',
      'directionalityltr',
      'directionalityrtl',
      'indent',
      '|',
      'justifyleft',
      'justifycenter',
      'justifyright',
      'justifyjustify',
      '|',
      'touppercase',
      'tolowercase',
      '|',
      'link',
      'unlink',
      'anchor',
      '|',
      'imagenone',
      'imageleft',
      'imageright',
      'imagecenter',
      '|',
      'horizontal',
      'spechars',
      'snapscreen',
      '|',
      'inserttable',
      'deletetable',
      'insertparagraphbeforetable',
      'insertrow',
      'deleterow',
      'insertcol',
      'deletecol',
      'mergecells',
      'mergeright',
      'mergedown',
      'splittocells',
      'splittorows',
      'splittocols',
      'charts'
    ]
  ],
  autoSaveEnable: false, // 禁用自动保存
  elementPathEnabled: false, // 禁用元素路径
  initialFrameHeight: '280',
  initialFrameWidth: '100%',
  autoHeightEnabled: false, // 禁止编辑器自动长高
  maximumWords: 1000000,
  zIndex: 10000
});

// 引入的js文件，这里是一定要写的。
const editorDependencies: string[] = reactive(['ueditor.config.js', 'ueditor.all.js', 'lang/zh-cn/zh-cn.js']);

const ueditor = ref<any | null>(null);

function readyHandle(editor: any) {
  ueditor.value = editor;
}

const emit = defineEmits<Emits>();

const visible = defineModel<boolean>('visible', {
  default: false
});

// 提示词
const prompt = ref<string>('');

function closeDrawer() {
  if (showLoading.value) return;
  visible.value = false;
  prompt.value = '';
  contentHtml.value = '';
  ueditor.value.clear();
  loadingDes.value = 'AI正在努力处理中，请稍后...';
  showLoading.value = false;
}

async function saveWriteClick() {
  emit('saveWrite', ueditor.value.getContent());

  setTimeout(() => {
    closeDrawer();
  }, 150)
}

// 快速填充
async function flashFillClick() {
  const params: any = {
    info_path: props.infoPath!.split(','),
    title: props.paragraphTitle
  };

  loadingDes.value = 'AI正在努力处理中，请稍后...';
  showLoading.value = true;
  const {data, error} = await contentFillAction(params);
  // console.log('分步生成: ', data.doc_path);
  showLoading.value = false;
  if (!error) {
    prompt.value = data.answer;
  }
}

// 快速编写
async function quicklyWriteClick() {
  const params: any = {
    task_id: props.taskId,
    tenant_id: '068259_111',
    zhaobiao_path: props.zhaobiaoPath,
    info_path: props.infoPath!.split(','),
    title: props.paragraphTitle,
    user_prompt: prompt.value
  };

  loadingDes.value = '小主，您的内容正在AI生成中，预计1分钟内完成，请稍后~';
  showLoading.value = true;
  const {data, error} = await stepGenerateAction(params);
  // console.log('分步生成: ', data.doc_path);
  showLoading.value = false;
  if (!error) {
    getHtmlByDocument(data.doc_path);
  }
}

// 根据文档获取html内容
function getHtmlByDocument(filePath: string) {
  const {VITE_OTHER_SERVICE_BASE_URL} = import.meta.env;
  const otherUrl = JSON.parse(VITE_OTHER_SERVICE_BASE_URL);
  const docPath: string = otherUrl.fileUrl + filePath;
  fetch(docPath, {cache: 'no-cache'})
    .then(response => response.blob())
    .then(blobData => {
      let file: File | null = new File([blobData], `${props.paragraphTitle}.docx`, {
        type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        lastModified: Date.now()
      });

      analysisWord(file).then(html => {
        // console.log("html: ", html);
        for (let i: number = 0; i < imgList.value.length; i++) {
          writeContentHtml.value = writeContentHtml.value.replace(IMAGE_TAG, imgList.value[i]);
        }
        ueditor.value.clear();
        // 设置内容到编辑器中
        ueditor.value.setContent(writeContentHtml.value, false);
        // ueditor.value.execCommand('inserthtml', writeContentHtml.value); // 插入文本
      });

      // 文件信息置空
      file = null;
    })
    .catch(error => {
      console.error('发生错误：', error);
      errorMessage('获取文档失败');
    });
}

// 解析word文件，将word转为html
function analysisWord(file: any) {
  return new Promise(resolve => {
    const reader = new FileReader();
    reader.onload = evt => {
      // 当文件读取完毕后
      // p标签首行没有缩进
      const options = {
        transformDocument: transformElement,
        styleMap: ["p[style-name='Section Title'] => h1:fresh", "p[style-name='Subsection Title'] => h2:fresh"]
      };

      // 调用mammoth组件的方法进行解析文件
      mammoth
        .convertToHtml({arrayBuffer: evt.target!.result}, options)
        .then(async resultObject => {
          // console.log("resultObject: ", resultObject);
          // resultObject.value = imgTagAddStyle(resultObject.value);
          const imgSrcReg = /<img[^>]+src=[\\'|\\"]?([^(?"|?'|?>)]+)[\\'|\\"]?[^>]*>/gim;
          const imgSrcList = resultObject.value.match(imgSrcReg);
          for (let i: number = 0; i < imgSrcList?.length; i++) {
            const imgSrc: string = imgSrcList[i].match(/src="(.+?)"/)[1];

            // console.log('imgSrc: ', imgSrc);
            const info = await getImageInfoFromBase64(imgSrc);
            if (info) {
              imgSrcList[i] =
                `${imgSrcList[i].substring(0, imgSrcList[i].length - 2)}width="${info.width}" height="${info.height}" ${imgSrcList[i].substring(imgSrcList[i].length - 2)}`;
            } else {
              imgSrcList[i] =
                `${imgSrcList[i].substring(0, imgSrcList[i].length - 2)}width="90%" height="auto" ${imgSrcList[i].substring(imgSrcList[i].length - 2)}`;
            }

            // 使用DOM解析器创建一个DOM元素
            // const domParser = new DOMParser();
            // const contentDom = domParser.parseFromString(imgSrcList[i], 'text/html');
            // const imgNode = contentDom.body.childNodes;
            //
            // console.log('imgNode: ', imgNode);
          }

          if (imgSrcList) {
            imgList.value = imgSrcList;
          }

          // console.log('imgList: ', imgList.value);
          resolve(resultObject.value); // 将处理好的html数据返回
          reader.abort(); // 关闭读取
        })
        .catch(err => {
          console.log('err: ', err);
          reader.abort(); // 关闭读取
        });
    };
    reader.readAsArrayBuffer(file);
    // 启动读取指定的 Blob 或 File 内容：https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader/readAsArrayBuffer
  });
}

// 给html标签中的img标签设置样式
function imgTagAddStyle(htmlstr: string) {
  // 正则匹配所有img标签
  // var regex0 = new RegExp("(i?)(\<img)([^\>]+\>)","gmi");
  // 正则匹配不含style="" 或 style='' 的img标签
  const regex1 = /(i?)(<img)(?!(.*?style=['"](.*)['"])[^>]+>)/gim;
  // 给不含style="" 或 style='' 的img标签加上style=""
  htmlstr = htmlstr.replace(regex1, '$2 style=""$3');
  // console.log(`增加style=""后的html字符串：${htmlstr}`);
  // 正则匹配含有style的img标签
  const regex2 = /(i?)(<img.*?style=['"])([^>]+>)/gim;
  // 在img标签的style里面增加css样式(这里增加的样式：display:block;max-width:100%;height:auto;border:5px solid red;)
  htmlstr = htmlstr.replace(regex2, '$2width:90%;height:auto;text-align:center;$3');
  // console.log(`在img标签的style里面增加样式后的html字符串：${htmlstr}`);
  return htmlstr;
}

// 元素重新定义
function transformElement(element: any) {
  if (element.children) {
    const children: any = _.map(element.children, transformElement);
    element = {...element, children};
  }

  if (element.type === 'paragraph') {
    element = transformParagraph(element);
  }

  if (element.type === 'document') {
    // docParagraphList.value = element.children;
    console.log('docParagraphList.value: ', element.children);
    htmlFormat(element.children);
  }

  return element;
}

// 段落内容重新定义
function transformParagraph(element: any) {
  if (element.alignment === 'center' && !element.styleId) {
    return {...element, styleId: 'Heading2'};
  }
  return element;
}

// 根据文档解析API进行HTML内容拼接封装
function htmlFormat(docParagraphList: any[]) {
  let docHtmlStr: string = '';
  for (let i: number = 0; i < docParagraphList.length; i++) {
    const paragraphObj: any = docParagraphList[i];
    if (paragraphObj.type === 'paragraph') {
      // 普通段落内容（包括文字和图片）
      let paragraphStr: string = '';
      let alignmentStr: string = '';
      if (paragraphObj.alignment) {
        alignmentStr = `text-align: ${paragraphObj.alignment}; line-height: 1.5; align-items: baseline;`;
      } else {
        alignmentStr = 'text-align: left; line-height: 1.5; align-items: baseline;';
      }

      for (let j: number = 0; j < paragraphObj.children.length; j++) {
        let isIndent: boolean = false;
        if (paragraphObj.children.length > 1 && j === 0 && paragraphObj.indent.firstLine) {
          isIndent = true;
        }
        const formatContent = paragraphHtmlFormat(paragraphObj.children[j], isIndent);
        if (formatContent === IMAGE_TAG) {
          alignmentStr = 'display: block;text-align: center;';
        }
        paragraphStr += formatContent;
      }
      if (paragraphObj.styleId === 'Heading1' || paragraphObj.styleName === 'heading 1') {
        docHtmlStr += `<h1 style="${alignmentStr}">${paragraphStr}</h1>`;
      } else if (paragraphObj.styleId === 'Heading2' || paragraphObj.styleName === 'heading 2') {
        docHtmlStr += `<h2 style="${alignmentStr}">${paragraphStr}</h2>`;
      } else if (paragraphObj.styleId === 'Heading3' || paragraphObj.styleName === 'heading 3') {
        docHtmlStr += `<h3 style="${alignmentStr}">${paragraphStr}</h3>`;
      } else if (paragraphObj.styleId === 'Heading4' || paragraphObj.styleName === 'heading 4') {
        docHtmlStr += `<h4 style="${alignmentStr}">${paragraphStr}</h4>`;
      } else if (paragraphObj.styleId === 'Heading5' || paragraphObj.styleName === 'heading 5') {
        docHtmlStr += `<h5 style="${alignmentStr}">${paragraphStr}</h5>`;
      } else if (paragraphObj.styleId === 'Heading6' || paragraphObj.styleName === 'heading 6') {
        docHtmlStr += `<h6 style="${alignmentStr}">${paragraphStr}</h6>`;
      } else {
        docHtmlStr += `<p style="${alignmentStr}">${paragraphStr}</p>`;
      }
    } else if (paragraphObj.type === 'table') {
      // 表格内容处理
      const tableObj: any = docParagraphList[i];
      docHtmlStr += tableHtmlFormat(tableObj);
    }
  }
  writeContentHtml.value = `<div style="margin: 72pt;">${docHtmlStr}</div>`;
}

// 段落内容格式化
function paragraphHtmlFormat(paragraphObj: any, isIndent: boolean) {
  let contentStr: string = '';

  // console.log("paragraphObj: ", paragraphObj);

  if (!paragraphObj.children) {
    return '<span></span>';
  }

  if (paragraphObj.children.length === 0) {
    return '<br/>';
  }

  for (let i: number = 0; i < paragraphObj.children.length; i++) {
    if (paragraphObj.children[i].type === 'text') {
      let textStr: string = paragraphObj.children[i].value;
      // 如果有html字符串，将其解析为html字符串，就可以正常展示
      textStr = escapeHTMLManually(textStr);

      let styleStr: string = `font-size: ${paragraphObj.fontSize}pt; font-family: ${paragraphObj.font};`;
      // 是否首行缩进
      if (isIndent) {
        styleStr += 'text-indent: 2em;';
      }
      // 是否有下划线
      if (paragraphObj.isUnderline) {
        styleStr += 'text-decoration: underline;';
      }
      // 是否有删除线
      if (paragraphObj.isStrikethrough) {
        styleStr += 'text-decoration: line-through;';
      }
      // if (paragraphObj.verticalAlignment) {
      //   styleStr += `display: block; align-items: ${paragraphObj.verticalAlignment};`;
      // }
      /** font: "fzxbsjw-gb1-0" fontSize: 32 */
      // 文档标题设置固定的色值：#E03E2D
      if (paragraphObj.fontSize === 32 && paragraphObj.font === 'fzxbsjw-gb1-0') {
        styleStr += 'color: #E03E2D;';
      }
      // 是否加粗(使用 strong 标签加粗内容)
      if (paragraphObj.isBold) {
        contentStr += `<strong style="${styleStr}">${textStr}</strong>`;
      } else {
        contentStr += `<span style="${styleStr}">${textStr}</span>`;
      }
    } else if (paragraphObj.children[i].type === 'break') {
      // 换行
      contentStr += '<br/>';
    } else if (paragraphObj.children[i].type === 'image') {
      // 图片
      contentStr += IMAGE_TAG;
    } else {
      contentStr = String(contentStr);
    }
  }

  return contentStr;
}

// 表格内容格式化
function tableHtmlFormat(tableObj: any) {
  let tableStr: string = '';
  const tableStyle: string = '';
  for (let i: number = 0; i < tableObj.children.length; i++) {
    // 遍历 tableRow
    const rowObj: any = tableObj.children[i];
    if (rowObj.isHeader) {
      tableStr += '<thead><tr>';
    } else {
      tableStr += '<tbody><tr>';
    }
    for (let j: number = 0; j < rowObj.children.length; j++) {
      // 遍历 tableCell
      const cellObj: any = rowObj.children[j];
      if (rowObj.isHeader) {
        tableStr += `<th style="${tableStyle}">`;
      } else {
        tableStr += `<td style="${tableStyle}">`;
      }
      for (let k: number = 0; k < cellObj.children.length; k++) {
        const contentObj: any = cellObj.children[k];

        let paragraphStr: string = '';
        let alignmentStr: string = '';
        if (contentObj.alignment) {
          alignmentStr = `text-align: ${contentObj.alignment};`;
        } else {
          alignmentStr = 'text-align: left;';
        }
        for (let l: number = 0; l < contentObj.children.length; l++) {
          let isIndent: boolean = false;
          if (contentObj.children.length > 1 && l === 0 && contentObj.indent && contentObj.indent.firstLine) {
            isIndent = true;
          }
          paragraphStr += paragraphHtmlFormat(contentObj.children[l], isIndent);
        }
        tableStr += `<p style="${alignmentStr}">${paragraphStr}</p>`;
      }
      if (rowObj.isHeader) {
        tableStr += '</th>';
      } else {
        tableStr += '</td>';
      }
    }
    if (rowObj.isHeader) {
      tableStr += '</thead></tr>';
    } else {
      tableStr += '</tbody></tr>';
    }
  }
  return `<table style="width: 100%; border-collapse: collapse;">${tableStr}</table>`;
}

// 重新编写
function againWriteClick() {
  quicklyWriteClick();
}
</script>

<template>
  <NDrawer v-model:show="visible" display-directive="show" :mask-closable="!showLoading" :width="1030">
    <NDrawerContent
      title="精细化编写"
      :header-style="{ fontSize: '18px', fontWeight: 'bold' }"
      :body-content-style="{ background: '#E8ECFD', height: '100%', padding: '20px 25px' }"
      :native-scrollbar="false"
      closable
    >
      <NCard>
        <NSpin :show="showLoading" :description="loadingDes" :rotate="false" size="large">
          <template #icon>
            <img src="@/assets/imgs/spin-loading.gif" alt="" width="240" height="240" />
          </template>
          <NScrollbar :style="{ height: '100%' }">
            <div class="header-box">
              <div class="header-tag">当前位置</div>
              <span class="header-text">{{ paragraphTitle }}</span>
            </div>
            <div class="center-title-box">
              <span class="center-tag">编写方向</span>
              <NButton class="center-btn" strong quaternary @click="flashFillClick">快速填充</NButton>
            </div>
            <div class="center-input-box">
              <NInput v-model:value="prompt" type="textarea" :maxlength="100" show-count placeholder="请输入"/>
            </div>
            <NSpace justify="end">
              <NButton class="quickly-btn" strong quaternary :disabled="showLoading" @click="quicklyWriteClick">
                快速编写
              </NButton>
            </NSpace>
            <div class="editor-box">
              <VueUeditorWrap
                v-model="contentHtml"
                editor-id="drawer_editor"
                :config="editorConfig"
                :editor-dependencies="editorDependencies"
                @ready="readyHandle"
              />
            </div>
            <NSpace v-if="contentHtml.length > 0" justify="end">
              <NButton class="rewrite-btn" strong quaternary :disabled="showLoading" @click="againWriteClick">重新编写
              </NButton>
            </NSpace>
          </NScrollbar>
        </NSpin>
      </NCard>
      <template #footer>
        <NSpace :size="16">
          <NButton class="submit-btn" strong quaternary :disabled="showLoading" @click="saveWriteClick">保存编写
          </NButton>
        </NSpace>
      </template>
    </NDrawerContent>
  </NDrawer>
</template>

<style scoped lang="scss">
.header-box {
  display: flex;
  flex-direction: column;
  .header-tag {
    font-weight: bold;
    font-size: 24px;
    color: #333333;
    line-height: 35px;
  }
  .header-text {
    font-size: 16px;
    color: #333333;
    line-height: 30px;
  }
}
.center-title-box {
  display: flex;
  flex-direction: row;
  align-items: flex-end;
  justify-content: space-between;
  margin-top: 15px;
  .center-tag {
    font-weight: bold;
    font-size: 24px;
    color: #333333;
    line-height: 35px;
  }
  .center-btn {
    width: 110px;
    height: 36px;
    background: #b59fff;
    border-radius: 4px;
    font-weight: 400;
    font-size: 16px;
    color: #ffffff;
    line-height: 36px;
  }
}
:deep(.n-spin) {
  width: auto;
  height: auto;
}
.quickly-btn {
  width: 140px;
  height: 40px;
  background: linear-gradient(180deg, #e877ae, #7c73f3);
  border-radius: 4px;
  font-weight: 400;
  font-size: 18px;
  color: #ffffff;
  line-height: 40px;
  border: none;
}
.editor-box {
  margin: 10px 0;
}
#drawer_editor {
  width: 100%;
  border: 1px solid #cccccc;
}
.rewrite-btn {
  width: 110px;
  height: 36px;
  background: #b59fff;
  border-radius: 4px;
  font-weight: 400;
  font-size: 16px;
  color: #ffffff;
  line-height: 36px;
  border: none;
}
.center-input-box {
  margin: 10px 0;
}
.submit-btn {
  width: 140px;
  height: 42px;
  background: linear-gradient(180deg, #e877ae, #7c73f3);
  border-radius: 4px;
  font-weight: 400;
  font-size: 16px;
  color: #ffffff;
  line-height: 42px;
  border: none;
}
</style>
